import moment from 'moment';

/**
 *   - 时间刻度间隔匹配规则：	两个点前后各预留一个时间点位间隔
 *   - code 1: 1天 ~ 3天  -> 按5分钟为一个刻度，8小时为一个点位间隔
 *   - code 2: 3天 ~ 7天  -> 按15分钟为一个刻度，12小时为一个点位间隔
 *   - code 3: 7天 ~ 30天 -> 按30分钟为一个刻度，一天为一个点位间隔
 *   - code 4: 1个月 ~ 6个月  -> 按1小时为一个刻度，一周为一个点位间隔
 *   - code 5: 6个月 ~ 36个月 -> 按1天为一个刻度，一个月为一个点位间隔
 *   - code 6: > 36个月按年   -> 按1天为一个刻度，年为一个点位间隔
 */
const timeRule = [
  { code: 1, step: 5, unit: 'minute', periodDesc: '8h', periodUnit: 'hour', dateFormat: 'YYYY-MM-DD HH:mm:ss', desc: '1天 ~ 3天' },
  { code: 2, step: 15, unit: 'minute', periodDesc: '12h', periodUnit: 'hour', dateFormat: 'YYYY-MM-DD HH:mm:ss', desc: '3天 ~ 7天' },
  { code: 3, step: 30, unit: 'minute', periodDesc: '1d', periodUnit: 'day', dateFormat: 'YYYY-MM-DD HH:mm:ss', desc: '7天 ~ 30天' },
  { code: 4, step: 1, unit: 'hour', periodDesc: '1w', periodUnit: 'week', dateFormat: 'YYYY-MM-DD HH:mm:ss', desc: '1个月 ~ 6个月' },
  { code: 5, step: 1, unit: 'day', periodDesc: '1M', periodUnit: 'month', dateFormat: 'YYYY-MM-DD HH:mm:ss', desc: '6个月 ~ 36个月' },
  { code: 6, step: 1, unit: 'day', periodDesc: '1y', periodUnit: 'year', dateFormat: 'YYYY-MM-DD HH:mm:ss', desc: '大于等于36个月' },
];

class TimelineRule {
  constructor() {}

  /**
   * 获取时间规则
   */
  getRule(startTime, endTime, unit) {
    const durationInfo = this.getDurationInfo(startTime, endTime, unit);
    const findRule = timeRule.find(o => o.code === durationInfo.code);
    let period = this.getPeriod(findRule.periodDesc, findRule.unit);

    // 如果是天作为步骤或刻度，则不需要时分秒，需要将时分秒设置为零
    if (findRule.unit === 'day') {
      startTime = moment(startTime).set({ hour: 0, minute: 0, second: 0 }).format(findRule.dateFormat);
      endTime = moment(endTime).set({ hour: 0, minute: 0, second: 0 }).format(findRule.dateFormat);
    }

    let firstTime = null;
    let lastTime = null;
    let max = 0;
    let min = 0;

    // 第一个时间规则，即 1 ~ 3 天，时间范围小于等于24小时的
    if (durationInfo.code === 1 && this.getDiffValue(startTime, endTime, 'hour') <= 48) {
      firstTime = moment(startTime).subtract(1, 'day').format(findRule.dateFormat);
      lastTime = moment(endTime).add(1, 'day').format(findRule.dateFormat);
      max = this.getDiffValue(firstTime, lastTime, 'minute');
    } else {
      // 其余规则
      firstTime = moment(startTime).subtract(period, findRule.unit).format(findRule.dateFormat);
      let diffDuration = this.getDiffValue(firstTime, endTime, findRule.unit);
      // 将第一个时间点与传入的结束时间的时长 与 时间段点位间隔 取模，等于0的部分均为时间轴上点位，不能完全取模的部分则为现有时间轴上最后一个点位超出的部分，默认向最后一个时间点位预留一个时间点位
      let exceedValue = diffDuration % period;
      lastTime = moment(endTime).add(period - exceedValue, findRule.unit).format(findRule.dateFormat);
      // 最大值取：第一个时间与结束时间的时间差 + (时间段间隔 - 取模剩余的值 = 最后一个点位的时间值)
      max = diffDuration + (period - exceedValue);
    }

    return Object.assign(findRule, {
      period,
      max,
      min,
      startTime,
      endTime,
      firstTime,
      lastTime,
      code: durationInfo.code,
      duration: durationInfo.duration,
      durationObj: durationInfo.durationObj,
    });
  }

  /**
   * 获取两个时间之间的时长，并转化为指定单位的数值
   * @param startTime 开始时间
   * @param endTime 结束时间
   * @param { 'minute' | 'hour' | 'day' } asUnit  转化时间单位
   */
  getDurationInfo(startTime, endTime, asUnit) {
    const durationMoment = moment.duration(moment(endTime).diff(moment(startTime)));
    const year = durationMoment.get('year');
    const month = durationMoment.get('month');
    const day = durationMoment.get('day');
    const hour = durationMoment.get('hour');
    const minute = durationMoment.get('minute');

    let code = -1;
    let unit = asUnit;

    /**
     * 时间轴优化：
     *   - 时间刻度间隔匹配规则：	两个点前后各预留一个时间点位间隔
     *   - code 1: 1天 ~ 3天  -> 按5分钟为一个刻度，8小时为一个点位间隔
     *   - code 2: 3天 ~ 7天  -> 按15分钟为一个刻度，12小时为一个点位间隔
     *   - code 3: 7天 ~ 30天 -> 按30分钟为一个刻度，一天为一个点位间隔
     *   - code 4: 1个月 ~ 6个月  -> 按小时为一个刻度，一周为一个点位间隔
     *   - code 5: 6个月 ~ 36个月 -> 按天为一个刻度，一个月为一个点位间隔
     *   - code 6: > 36个月按年   -> 按天为一个刻度，年为一个点位间隔
     */
    if (year >= 3) {
      // 时长超过3年(大于等于36个月) -> 按天为一个刻度，年为一个点位间隔
      unit = 'day';
      code = 6;
    } else if (year > 0 || month > 6 || (month === 6 && day > 0)) {
      // 6个月 ~ 36个月 -> 按天为一个刻度，一个月为一个点位间隔
      unit = 'day';
      code = 5;
    } else if (month >= 1 && month <= 6) {
      // 1个月 ~ 6个月  -> 按小时为一个刻度，一周为一个点位间隔
      unit = 'hour';
      code = 4;
    } else {
      unit = 'minute';
      if (day <= 3) {
        // 1天 ~ 3天  -> 按5分钟为一个刻度，8小时为一个点位间隔
        code = 1;
      } else if ((day > 3 || (day === 3 && hour > 0)) && day <= 7) {
        // 3天 ~ 7天  -> 按15分钟为一个刻度，12小时为一个点位间隔
        code = 2;
      } else {
        // 7天 ~ 30天 -> 按30分钟为一个刻度，一天为一个点位间隔
        code = 3;
      }
    }

    return {
      durationObj: { year, month, day, hour, minute },
      duration: durationMoment.as(asUnit || unit),
      code,
    };
  }

  /**
   * 获取时间段点位间隔，转化为分钟
   * @param str 需要转化的时间字符串: '8h' | '5d' | '3w' | '2M' | '1y'
   * @param { 'minute' | 'hour' | 'day' | 'week' } asUnit 需要转化的时间单位: 'minute' | 'hour' | 'day' | 'week'
   * @returns {*}
   */
  getPeriod(str, asUnit = 'minute') {
    let arr = str.replace(/^(\d.*)([hdwMy])$/, '$1,$2').split(',');
    return this.getDurationOfAsUnit(arr[0], arr[1], asUnit);
  }

  /**
   * 获取分钟数
   * @param num 数量
   * @param unit 当前时间单位 (h | d | w | M | y)分别对应 --> (时 | 天 | 周 | 月 | 年)
   * @param asUnit 需要转化的时间单位
   * @returns {number}
   */
  getDurationOfAsUnit(num, unit = 'h', asUnit = 'minute') {
    return moment.duration(num, unit).as(asUnit);
  }

  /**
   * 获取最大值
   */
  getDiffValue(startTime, endTime, unitOfTime) {
    return moment(endTime).diff(moment(startTime), unitOfTime);
  }
}

export default new TimelineRule();
